<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    /*
    // 工厂模式
    // 优点:  可以根据传入的参数 快速生成对应的对象
    // 缺点:
    // a. 通过函数创建对象 和 函数本身 没有关联 (相对于构造函数)
    // b. 公有的属性和方法 重复声明,栈内存
    */


    // 通过自定义构造函数 解决了 问题1:(通过函数创建对象 和 函数本身 没有关联)

    function Cat(name, color) {
        // {}
        // this -> {}
        this.name = name;
        this.color = color;

        // 公有的属性和方法  => 重复声明占据内存  => 提取到公共的位置(存储一次)
        // this.species = "猫";
        // this.call = function () {
        //     console.log("喵喵");
        // }
        // this.skill = function () {
        //     console.log("捉老鼠");
        // }
        // this.say = function () {
        //     console.log(this.name, this.age);
        // }
        // return this;
    }

    // 函数的本质也是一个对象(new Function())  => 也可以有自己的属性和方法    

    // 静态属性和方法   =>  构造函数自己的方法  
    // Cat.hello = "你好";
    // Cat.isCat = function (arg) {
    //     return arg instanceof Cat;
    // }

    // prototype  原型对象
    // 公有的属性和方法  => 重复声明占据内存  => 提取到一个公共的位置 允许所有的实例化对象访问  =>   prototype 
    // 致力于 将实例化对象所有公有的属性和方法 提取出来  放到公共的位置prototype   允许所有的实例化对象访问

    // Cat.prototype = {constructor}
    Cat.prototype.species = "猫";
    Cat.prototype.call = function () {
        console.log("喵喵");
    };
    Cat.prototype.skill = function () {
        console.log("捉老鼠");
    }

    // say方法虽然存储在原型对象上( Cat.prototype)  但是由实例化对象调用 => 
    Cat.prototype.say = function () {
        // this => 指向调用此方法的实例化对象(函数在调用时  属于谁就指向谁)
        console.log(this.name, this.color);
    }
    console.dir(Cat);


    var Tom = new Cat("Tom", "black");
    console.log(Tom, Tom instanceof Cat);

    // 自己有先找自己的  (查找实例自身)
    console.log(Tom.name, Tom.color);

    console.group("a");
    // 自己没有就找构造函数Cat的原型对象  => Cat.prototype
    console.log(Tom.species);
    console.log(Tom.call);
    console.log(Tom.say);
    Tom.call();
    Tom.say(); // 函数在调用时  属于谁就指向谁
    console.groupEnd("a");

    console.group("b");
    var Kitty = new Cat("Kitty", "pink");
    console.log(Kitty, Kitty instanceof Cat);

    console.log(Kitty.species);
    console.log(Kitty.call);
    console.log(Kitty.say);
    Kitty.call();
    Kitty.say(); // 函数在调用时  属于谁就指向谁
    console.groupEnd("b");
</script>

</html>